import {CONTROLLER, MODULE, PROPERTY, ROUTER_METHOD, ROUTER_PATH} from "./constant";
import { ModuleMetadata } from "./core";
import {Application, Request, Response} from "express";
import express from "express";
import bodyParser  from 'body-parser'
import { isPromise } from './is-type'


class NestFactoryStatic {
   create(module: any) {
    const metadata = Reflect.getMetadata(MODULE, module) as ModuleMetadata

    if (metadata) {
      const routes = this.getRouts(metadata)

      if (routes.length > 0) {
        const app = express()

        app.use(bodyParser.json())
        app.use(bodyParser.raw())
        app.use(bodyParser.urlencoded({ extended: false }))

        routes.forEach((route: any) => {
          const { path, method, fn } = route

          app[method as keyof Application](path, fn)
        })

        app.listen(3000, () => {
          console.log('服务已经启动')
          console.log('服务地址:', 'http://localhost:3000')
        })
      }
    }
  }

  private createRouterMethod(object: any, key: string) {
    return (req: Request, res: Response) => {
      const target = object.prototype

      // 这里是获取方法的入参的数据类型
      const params = Reflect.getMetadata('design:paramtypes', target, key)

      const method = target[key as keyof typeof target] as any
      const args: any[] = []

      if (params && params.length > 0) {
        // 带参数的
        const property = Reflect.getMetadata(PROPERTY, target, key) as []

        for (let i = 0; i < property.length; i++) {
          const { type, index, Validate } = property[i] as  any
          // 请求中body或者query的数据
          const value = req[type as keyof Request]

          if (Validate) {
            try {
              new Validate().transform(value, params[index].prototype)
            } catch (err) {
              res.send(err)
              return
            }
          }

          const instance = new params[index]

          Object.keys(value).forEach((key) => {
            instance[key] = value[key]
          })

          args[index] = instance
        }
      }

      const objectParams = Reflect.getMetadata('design:paramtypes', object);
      let objectArgs = []

      if (objectParams) {
        objectArgs = objectParams.map((p: any) => {
          return new p()
        })
      }

      // todo 这里有问题，每次请求都会new 一个控制器
      const instance = new object(...objectArgs)
      const v = method.apply(instance, args)

      if (isPromise(v)) {
        v.then((data) => {
          res.send(data)
        }).catch((err) => {
          res.send(err)
        })
      } else {
        res.send(v)
      }
    }
  }

  private getRouts(metadata: ModuleMetadata) {
     const { imports, controllers } = metadata

    const routes: any[] = []

    if (controllers) {
      controllers.forEach((controller) => {
        const controllerPath = Reflect.getMetadata(CONTROLLER, controller)

        Object.getOwnPropertyNames(controller.prototype).forEach((key) => {
          if (typeof controller.prototype[key] === 'function' && key !== 'constructor') {
            const path = Reflect.getMetadata(ROUTER_PATH, controller.prototype, key)
            const method = Reflect.getMetadata(ROUTER_METHOD, controller.prototype, key)

            routes.push({
              path: `/${controllerPath}/${path}`,
              method,
              fn: this.createRouterMethod(controller, key)
            })
          }
        })
      })
    }

    if (imports) {
      imports.forEach((module) => {
        const metadata = Reflect.getMetadata(MODULE, module) as ModuleMetadata

        metadata && routes.push(...this.getRouts(metadata))
      })
    }

    return routes
  }
}


export const NestFactory = new NestFactoryStatic()
